#include "napi_utils.h"
#include <codecvt>
#include <cstdio>
#include <cstring>
#include <locale>
#include <string>
#include <string.h>
#include "../ohoslog/ohos_log.h"

const int32_t MAX_STR_LENGTH = 1024;
void NapiUtil::JsValueToString(const napi_env & env, const napi_value & value, const int32_t bufLen, std::string & target)
{
    if (bufLen <= 0 || bufLen > MAX_STR_LENGTH) {
        LOGI("%s string too long malloc failed", __func__);
        return;
    }

    std::unique_ptr < char[] > buf = std::make_unique < char[] >(bufLen);
    if (buf.get() == nullptr) {
        LOGI("%s nullptr js object to string malloc failed", __func__);
        return;
    }
    (void)memset(buf.get(), 0, bufLen);
    size_t result = 0;
    napi_get_value_string_utf8(env, value, buf.get(), bufLen, &result);
    target = buf.get();
}

void NapiUtil::JsObjectToString(const napi_env & env, const napi_value & object, std::string fieldStr,
                                const int32_t bufLen, std::string & fieldRef)
{
    if (bufLen <= 0)
        return;

    bool hasProperty = false;
    napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty);
    if (hasProperty) {
        napi_value field;
        napi_valuetype valueType;

        napi_get_named_property(env, object, fieldStr.c_str(), &field);
        napi_typeof(env, field, &valueType);
        NAPI_ASSERT_RETURN_VOID(env, valueType == napi_string, "Wrong argument type. String expected.");
        std::unique_ptr < char[] > buf = std::make_unique < char[] >(bufLen);
        if (buf.get() == nullptr) {
            LOGI("%s nullptr js object to string malloc failed", __func__);
        }
        (void)memset(buf.get(), 0, bufLen);
        size_t result = 0;
        napi_get_value_string_utf8(env, field, buf.get(), bufLen, &result);
        fieldRef = buf.get();
    } else {
        LOGI("%s js to str no property: %s", __func__, fieldStr.c_str());
    }
}

bool NapiUtil::JsObjectGetProperty(const napi_env & env, const napi_value & object, std::string fieldStr,
                                   napi_value & value)
{
    bool hasProperty = false;
    napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty);
    if (hasProperty) {
        napi_get_named_property(env, object, fieldStr.c_str(), &value);
    } else {
        LOGI("%s js object has no property: %s", __func__, fieldStr.c_str());
    }
    return hasProperty;
}

void NapiUtil::JsObjectToInt(const napi_env & env, const napi_value & object, std::string fieldStr, int32_t & fieldRef)
{
    bool hasProperty = false;
    napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty);
    if (hasProperty) {
        napi_value field;
        napi_valuetype valueType;

        napi_get_named_property(env, object, fieldStr.c_str(), &field);
        napi_typeof(env, field, &valueType);
        NAPI_ASSERT_RETURN_VOID(env, valueType == napi_number, "Wrong argument type. Number expected.");
        napi_get_value_int32(env, field, &fieldRef);
    } else {
    }
}

bool NapiUtil::JsUint8ArrayParse(const napi_env & env, const napi_value & object, uint8_t ** uint8Buffer,
                                 size_t & bufferSize, size_t & offset)
{
    bool isTypedArray = false;
    if (napi_is_typedarray(env, object, &isTypedArray) != napi_ok || !isTypedArray) {
        return false;
    }

    napi_typedarray_type type;
    napi_value buffer;

    napi_status infoStatus =
    napi_get_typedarray_info(env, object, &type, &bufferSize, (void **)uint8Buffer, &buffer, &offset);
    if (infoStatus != napi_ok) {
        return false;
    }

    if (type != napi_uint8_array) {
        return false;
    }

    return true;
}

void NapiUtil::Uint8ArrayToJsValue(const napi_env & env, std::vector < uint8_t > & uint8Buffer, size_t bufferSize,
                                   napi_value & result)
{
    if (bufferSize < 0) {
        napi_get_undefined(env, &result);
        return;
    }

    uint8_t * nativeArraybuffer = nullptr;
    napi_value nativeValue = nullptr;
    napi_create_arraybuffer(env, bufferSize, (void **)&nativeArraybuffer, &nativeValue);
    memcpy(nativeArraybuffer, (const char *)uint8Buffer.data(), bufferSize);
    napi_create_typedarray(env, napi_uint8_array, bufferSize, nativeValue, 0, &result);
}

void NapiUtil::SetValueUtf8String(const napi_env & env, std::string fieldStr, std::string str, napi_value & result)
{
    napi_value value;
    napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &value);
    napi_set_named_property(env, result, fieldStr.c_str(), value);
}

void NapiUtil::SetValueInt32(const napi_env & env, std::string fieldStr, const int32_t intValue, napi_value & result)
{
    napi_value value;
    napi_create_int32(env, intValue, &value);
    napi_set_named_property(env, result, fieldStr.c_str(), value);
}

void NapiUtil::SetValueBool(const napi_env & env, std::string fieldStr, const bool boolValue, napi_value & result)
{
    napi_value value;
    napi_get_boolean(env, boolValue, &value);
    napi_set_named_property(env, result, fieldStr.c_str(), value);
}

napi_value NapiUtil::SetNapiCallBool(napi_env env, bool value)
{
    napi_value temp;
    napi_value result;
    napi_create_int32(env, value == true ? 1 : 0, &temp);
    napi_coerce_to_bool(env, temp, &result);
    return result;
}